home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / Documents / NeXTAnswers / objc.219 < prev    next >
Text File  |  1992-02-06  |  4KB  |  63 lines

  1. {\rtf0\ansi{\fonttbl\f3\fnil Times-Roman;\f0\fmodern Courier;}
  2. \paperw13040
  3. \paperh10200
  4. \margl120
  5. \margr120
  6. \pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\f3\b0\i0\ul0\fs28 message overhead objc\
  7. \
  8. Q:  My Objective-C messages take too long compared with C function calls.  What can I do?\
  9. \
  10. A:  We have chosen to pay a certain performance cost in exchange for the benefits of object-oriented programming.  What is really important is to amortize the added overhead of a message send over the cost of running your program.  The cost of writing and maintaining correct code is also a consideration.\
  11. \
  12. There is a way to optimize tight loops in code.  The method "methodFor:" returns a pointer to the actual function used to implement a method.  This can be used at the beginning of a tight loop to cache the call.  Example:\
  13. \
  14.  
  15. \f0\fs24     IMP func;\
  16.     \
  17.     func = [anObject methodFor:aSelector];\
  18.     while (loopingTightly) \{\
  19.         ...\
  20.         func(anObject, @selector(aSelector), args ...);\
  21.         ...\
  22.     \}\
  23.  
  24. \f3\fs28 \
  25. As long as anObject is not changing value in that inner loop, then this technique does not sacrifice any of the advantages of Objective-C (e.g., dynamic binding) and is just as efficient as normal C.\
  26. \
  27. However, there is a very subtle error that can be introduced by using the methodFor: method to get the pointer to the implementation of a method.   methodFor: returns an IMP which is a pointer to a function which returns an id.  It is prototyped to take an id, a SEL, and then a variable number of arguments, which are, of course, unprotoyped because depending on the method, those arguments could be anything.  This lack of a complete ANSI prototype can produce ill effects.  Without prototypes, arguments are subject to promotion.  Chars are promoted to int,  floats are promoted to double, and so on.  \
  28. \
  29. The concern is with floats.  Let's say you have a method that takes a float as an argument.  Objective-C methods conform to the ANSI prototyping rules and expect a 32-bit float to be put on the stack for that method.  And when that method is called normally, 32 bits are put on the stack and it all works out.  \
  30. \
  31. Now you get the IMP by calling methodFor: for that selector.  You try to directly call the function,  passing a float.  Because the function was not explicitly prototyped, old-style C takes over and that float is promoted to a 64-bit double.  When that 64 bits is placed on the stack for a method which expects a 32-bit float — catastrophe strikes!  The method tries to interpret the first 32 bits of the 64-bit double as a float, which doesn't work, and any arguments which follow the float in the parameter list are also messed up.\
  32. \
  33. The solution:  construct the proper prototype for the function pointer in question , something like this:\
  34. \
  35.  
  36. \f0\fs24      id   (*func)(id,SEL,float,...); \
  37.      \
  38.      func = (id (*)(id,SEL,float,...))[anObject methodFor:@selector(aSelector)];
  39. \f3\fs28 \
  40.      
  41. \f0\fs24    (* func)(anObject, @selector(aSelector), aFloat, otherArgs ...);\
  42.  
  43. \f3\fs28 \
  44. The prototype ensures that methodFor: returns a pointer to a function that returns an id and has the arguments an id, a selector, a float, and other variable arguments.  If the sight of prototypes scares you, another solution is to structure the necessary methods to simply take doubles.\
  45. \
  46. You must take similar precautions and coerce the return value when the method does not return an id.  Here floatValue is a method which returns a float.\
  47. \
  48.  
  49. \f0\fs24     float   (*getFloat)();\
  50.     float    value;\
  51.     \
  52.     getFloat = (float (*)())[anObject methodFor:@selector(floatValue)];\
  53.     value = (* getFloat)(anObject, @selector(floatValue)));\
  54.  
  55. \f3\fs28 \
  56. \
  57. QA219\
  58. \
  59. Valid for 1.0\
  60. Valid for 2.0\
  61. \
  62.  
  63.